/******************************************************************************\
    ContestantCookieDataBase.h discribes a database of ties of contestants 
	 and cookies.
    It's used for acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once

#include ".\BaseDataBase.hpp"

namespace nsContestantCookieDataBase
{
	const size_t MAX_COOKIE_LENGTH = 31;
	
	struct sContestantCookieData0
	{
		unsigned long Key;
		unsigned long ContestantId;
		char Cookie[ MAX_COOKIE_LENGTH + 1 ];
		unsigned long long TimeUp;
	};

	struct sContestantCookieData1
	{
		unsigned long Key;
		unsigned long ContestantId;
		char Cookie[ MAX_COOKIE_LENGTH + 1 ];
		unsigned long long TimeUp;
	};

	typedef sContestantCookieData1 sContestantCookieData;

	void ConversionFunction0( void *new_data, const void *prev_data );

	const sConversionTable ConversionTable[] = 
	{
		{ sizeof( sContestantCookieData0 ), sizeof( sContestantCookieData1 ), &ConversionFunction0 }
	};

	struct CookieCompare : public std::binary_function< cDataPointer< sContestantCookieData >, cDataPointer< sContestantCookieData >, bool >
	{
		bool operator()( const cDataPointer< sContestantCookieData > &left, const cDataPointer< sContestantCookieData > &right ) const
		{
			return strcmp( left->Cookie, right->Cookie ) < 0;
		}
	};

	typedef cBaseDataBase< sContestantCookieData >::KeyIterator KeyIterator;
	typedef cPublicIterator< sContestantCookieData, CookieCompare > CookieIterator;

	class cWardContestantCookieDataBase : public cBaseDataBase< sContestantCookieData >
	{
	private:
		std::set< cDataPointer< sContestantCookieData >, CookieCompare > CookieIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sContestantCookieData > &data_pointer )
		{
			return CookieIndex.find( data_pointer ) != CookieIndex.end();
		}
		virtual void InsertIndex( const cDataPointer< sContestantCookieData > &data_pointer )
		{
			CookieIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sContestantCookieData > &data_pointer, unsigned long index )
		{
			CookieIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sContestantCookieData > &data_pointer )
		{
			CookieIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			CookieIndex.clear();
		}
	public:
		cWardContestantCookieDataBase( /*bool auto_update*/ )
			: cBaseDataBase( /*auto_update*/ )
		{
		}
		CookieIterator BeginByCookie() const
		{
			return CookieIterator( CookieIndex.begin() );
		}
		CookieIterator FindByCookie( const char cookie[] ) const
		{
			if( strlen( cookie ) > MAX_COOKIE_LENGTH )
				return EndByCookie();
			sContestantCookieData contestant_cookie_data;
			strcpy( contestant_cookie_data.Cookie, cookie );
			return CookieIterator( CookieIndex.find( cDataPointer< sContestantCookieData >( &contestant_cookie_data ) ) );
		}
		CookieIterator EndByCookie() const
		{
			return CookieIterator( CookieIndex.end() );
		}
		bool GetByCookie( const char cookie[], sContestantCookieData &contestant_cookie_data ) const
		{
			cLocker locker( *this );
			CookieIterator iterator = FindByCookie( cookie );
			if( iterator == EndByCookie() )
				return false;
			contestant_cookie_data = *iterator;
			return true;
		}
	};

	class cContestantCookieDataBase : public cPointerObject< cWardContestantCookieDataBase >
	{
	public:
		bool Create( /*bool auto_update = false*/ )
		{
			cWardContestantCookieDataBase *ward_contestant_cookie_data_base;
			try
			{
				ward_contestant_cookie_data_base = new cWardContestantCookieDataBase( /*auto_update*/ );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_contestant_cookie_data_base ) )
			{
				delete ward_contestant_cookie_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
